package cn.wen.controller;

import cn.wen.common.enums.*;
import cn.wen.common.service.RedisService;
import cn.wen.common.utils.DateUtils;
import cn.wen.common.utils.ResultEntity;
import cn.wen.entity.UserEntity;
import cn.wen.service.*;
import cn.wen.shiro.JwtUtil;
import cn.wen.shiro.token.JwtToken;
import cn.wen.vo.*;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Param;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.*;


/**
 * @author yaling
 * @email 932043654
 * @date 2022-08-01 21:52:40
 */
@Slf4j
@RestController
@RequestMapping("/web")
public class UserController {


    @Autowired
    private UserService userService;

    @Autowired
    private LogService logService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private MSGService msgService;

    @Autowired
    private CollectLikeService collectLikeService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private NoticesService noticesService;

    @Autowired
    private GoodsService goodsService;

    /**
     * 自定义token登录
     * @param user
     * @return
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String login(@RequestBody UserEntity user, HttpServletRequest request) {
        String account = user.getUserId() == null ? user.getUserPhone() : user.getUserId();
        if (("".equals(account) || account == null)
                || user.getPassword() == null) {
            return JSON.toJSONString(ResultEntity.error(500,"账号密码不能为空"));
        }
        Subject subject = SecurityUtils.getSubject();
        // 有效期为 1 day
        String token = JwtUtil.createJWT(account, "second", "user", 1000 * 60 * 60 * 24);
        // 创建一个token
        JwtToken jwtToken = new JwtToken(token, user.getPassword());
        try {
            subject.login(jwtToken);
        } catch (UnknownAccountException e) {
            return JSON.toJSONString(ResultEntity.error(401,"账号不存在"));
        } catch (IncorrectCredentialsException e) {
            return JSON.toJSONString(ResultEntity.error(402,"密码错误"));
        }
        // 获取用户信息传输到前端
        UserEntity resultUser = userService.getUserByAccount(account);
        request.getSession().setAttribute("loginUser", resultUser);
        Map<String, Object> map = new HashMap<>();
        // 获取用户节点的数据
        map.put("user", resultUser);
        map.put("token", token);
        logService.log(resultUser, request, Log.LOGIN, SysType.WECHAT);
        return JSON.toJSONString(ResultEntity.ok("登录成功！").put("user", map));
    }

    /**
     * 退出登录
     * @return
     */
    @GetMapping("/logout")
    public ResultEntity logout() {
        SecurityUtils.getSubject().logout();
        return ResultEntity.ok("成功登出！");
    }

    /**
     * 通过短信验证实现修改密码  通过短信验证就不需要旧密码
     * 修改密码的途径  就是先调用phone/code 校验
     * 然后点击修改密码
     * @param user
     * @return
     */
    @PostMapping("/user/update")
    public ResultEntity updateUser(@RequestBody UserEntity user) {
        // user中的就是新密码
        boolean result = userService.updateUser(user);
        if (!result) return ResultEntity.error(200, "更新失败！");
        return ResultEntity.ok("更新成功！");
    }

    /**
     * 验证码操作业务  点击获取验证码按钮
     * @param userPhone
     * @return
     */
    @RequestMapping(value = "/phone/code", method = RequestMethod.POST)
    public ResultEntity sendCode(@RequestParam("userPhone") String userPhone) {
        // 这里通过 默认添加数据来实现
        // 判断当前账号是否存在
        if (userService.checkUserByUserPhone(userPhone)) {
            // 账号存在
            return ResultEntity.error(500, "该手机号已存在！");
        }
        // 判断当前账号是否超过五次
        if (redisService.hasKey("time:" + userPhone)) {
            // 存在该账号说明已经发生过一次请求验证
            // 判断请求是否超过5次 大于等于5次就不能再发生请求  第二天刷新
            if (redisService.getInteger("time:" + userPhone) >= 5) {
                return ResultEntity.error("你的手机号当前超过验证次数，请你第二天再执行请求！");
            }
            // 如果没有超过则再进行操作
        } else {
            // 当前还未进行短信验证  设置当前剩余秒的timeout
            redisService.setInteger("time:" + userPhone, 0, DateUtils.getDaysOfDay());
        }
        // 发送短信验证
        String code = "";
        try {
            code = msgService.send(userPhone);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultEntity.error(500, "服务器异常！发送短信验证失败！");
        }
        // 实现一次自增  设置自增步长
        redisService.incr("time:" + userPhone, 1);
        // 将code存储到redis中  有效期为5分钟  如果在5分钟内重新点击会覆盖原有的  同时刷新有效期
        redisService.setString("code:" + userPhone, code, 5 * 60);
        return ResultEntity.ok();
    }

    /**
     * 更改手机绑定  传入code  和手机号  用户id 实现更改绑定
     * @param bindPhoneVO
     * @return
     */
    @RequestMapping(value = "/phone/binding-update", method = RequestMethod.POST)
    public ResultEntity updatePhone(@RequestBody BindPhoneVO bindPhoneVO) {
        // 校验当前code是否成功
        if (!redisService.hasKey("code:" + bindPhoneVO.getUserPhone())) {
            return ResultEntity.error("验证码还未发送成功到或者已经过期!");
        }
        // 校验验证码
        String phoneCode = redisService.getString("code:" + bindPhoneVO.getUserPhone());
        if (!phoneCode.equals(bindPhoneVO.getCode())) {
            return ResultEntity.error(HttpCode.错误请求.getCode(),"验证码错误，请你重新输入！");
        }
        UserEntity userEntity = new UserEntity();
        userEntity.setUserId(bindPhoneVO.getUserId());
        userEntity.setUserPhone(bindPhoneVO.getUserPhone());
        userService.updateUser(userEntity);
        redisService.del("code:" + bindPhoneVO.getUserPhone());
        return ResultEntity.ok();
    }


    /**
     * 将手机号和系统创建的账号Id作为登录的途径
     * 默认账号密码为yl12345678
     * 点击注册自动登录到小程序  提示修改密码
     * 注册完默认登录页面
     * @param userPhone
     * @return
     */
    @RequestMapping(value = "/register", method = RequestMethod.POST)
    public ResultEntity register(@RequestParam("userPhone") String userPhone, @RequestParam("code") String code) {
        // 校验当前code是否成功
        if (!redisService.hasKey("code:"+userPhone)) {
            return ResultEntity.error("验证码还未发送成功到或者已经过期！");
        }
        // 校验验证码
        String phoneCode = redisService.getString("code:" + userPhone);
        if (!phoneCode.equals(code)) {
            return ResultEntity.error("验证码错误，请你重新输入！");
        }
        userService.insert(userPhone);
        redisService.del("code:" + userPhone);
        return ResultEntity.ok();
    }

    /**
     * 通过短信验证实现修改密码  通过短信验证就不需要旧密码
     * 修改密码的途径  就是先调用phone/code 校验
     * 然后点击修改密码
     * @return
     */
    @GetMapping("/user/userInfo")
    public ResultEntity getUserInfo(@RequestParam("userId") String userId) {
        // 我的主界面获取的全部数据  登录返回了user信息  我们目前主要将我的界面的全部数据返回
        // 1、点赞 和  收藏数据  浏览记录
        // 1.1、点赞获取
        Long likeNum = collectLikeService.getCollectLikeNumByUser(userId, CollectLike.LIKE.getType());
        // 1.2、收藏获取
        Long collectNum = collectLikeService.getCollectLikeNumByUser(userId, CollectLike.COLLECT.getType());
        // 1.3、浏览记录获取
        Long browsingHistoryNum = userService.getBrowsingHistoryNumByUser(userId);
        // 2、待支付、待发货、退换正在状态  则需要标红点
        // 2.1、待支付数据
        Long waitPayNum = orderService.getOrderNumByUser(userId, OrderStatus.WAIT_PAY.getStatus());
        // 2.2、待发货
        Long waitDeliveryNum = orderService.getOrderNumByUser(userId, OrderStatus.WAIT_DELIVER.getStatus());
        // 2.3、待收货
        Long waitReceiveNum = orderService.getOrderNumByUser(userId, OrderStatus.WAIT_RECEIVE.getStatus());
        // 2.4、退货
        Long cancelOrderNum = orderService.getOrderNumByUser(userId, OrderStatus.CANCEL_ORDER.getStatus());

        // 3、我的信息有新通知则需要标红
        Long newNoticesNum = noticesService.getNoticesNewNumByUser(userId, Notices.NEW_NOTICES.getCode());
        Map<String, Long> map = new HashMap<>();
        map.put("likeNum", likeNum);
        map.put("collectNum", collectNum);
        map.put("browsingHistoryNum", browsingHistoryNum);
        map.put("waitPayNum", waitPayNum);
        map.put("waitDeliveryNum", waitDeliveryNum);
        map.put("waitReceiveNum", waitReceiveNum);
        map.put("cancelOrderNum", cancelOrderNum);
        map.put("newNoticesNum", newNoticesNum);
        return ResultEntity.ok().put("data", map);
    }

    /**
     * 获取用户个人信息
     * @param userId
     * @return
     */
    @GetMapping("/user/personal-info")
    public ResultEntity userInfo(@RequestParam("userId") String userId) {
        UserEntity userByAccount = userService.getUserByAccount(userId);
        return ResultEntity.ok().put("userInfo", userByAccount);
    }

    /**
     * 获取浏览记录
     * @param userId
     * @return
     */
    @GetMapping("/user/browsing")
    public ResultEntity browsingHistory(@RequestParam("userId") String userId) {
        List<BrowsingGoodsVO> goodsVOList = userService.getBrowsingHistoryByUser(userId);
        return ResultEntity.ok().put("data", goodsVOList);
    }

    /**
     * 删除浏览记录
     * @RequestBody browsingUserVO
     * @return
     */
    @PostMapping("/user/browsing/delete")
    public ResultEntity browsingHistoryDeleteById(@RequestBody BrowsingUserVO browsingUserVO) {
        boolean isDelete = userService.deleteByUserIdAndGoodsId(browsingUserVO.getUserId(), browsingUserVO.getGoodsId());
        if (!isDelete) return ResultEntity.error(HttpCode.内部服务器错误.getCode(), "删除失败！");
        return ResultEntity.ok();
    }

    /**
     * 当前用户全部已经上架的物品
     * 只能拥有超级用户的角色才能操作
     */
    @GetMapping("/user/store/goods-list")
    public ResultEntity userStore(@RequestParam ("userId") String userId){
        List<GoodsVO> goodsList = goodsService.getGoodsListByUserIdStatus(userId, GoodsStatus.SOLD_IN.getCode());
        return ResultEntity.ok().put("data", goodsList);
    }

    /**
     * 获取微信的权限  绑定微信账号
     * @param userEntity
     * @return
     */
    @PostMapping("/user/authorization")
    public ResultEntity userAuthorization(@RequestBody UserEntity userEntity) {
        // 将用户的openid存储到数据库中存储
        boolean b = userService.updateUser(userEntity);
        if (!b) return ResultEntity.error(HttpCode.内部服务器错误.getCode(), "存储权限失败！");
        return ResultEntity.ok();
    }

}
